<?php
declare(strict_types=1);

namespace ExpressionEngine\LexicalAnalysisEngine;

use Contract\Exceptions\LogicException;
use ExpressionEngine\LexicalAnalysisEngine\Enum\LexicalAnalysisEnum;
use ExpressionEngine\Utils\StringUtil;

class LexicalAnalysisExpression
{
    protected LexicalAnalysisTag $lexicalAnalysisTag;

    public function __construct(LexicalAnalysisTag $lexicalAnalysisTag)
    {
        $this->lexicalAnalysisTag = $lexicalAnalysisTag;
    }

    /**
     * @param string $expression
     * @return array
     * @throws LogicException
     */
    public function scan(string $expression): array
    {
        $childExpressionList = [];
        $stack = [];
        $length = strlen($expression);
        for ($i = 0; $i < $length; $i++) {
            if (strcmp($expression[$i], '(') == 0) {
                array_unshift($stack, $i);
            }
            if (strcmp($expression[$i], ')') == 0) {
                $childExpressionId = count($childExpressionList);
                $childExpressionStartIndex = array_shift($stack);
                $childExpressionLength = $i - $childExpressionStartIndex + 1;
                $childExpressionList = $this->replaceChildExpression($expression, $childExpressionList, $childExpressionStartIndex, $childExpressionLength, $childExpressionId);
            }
        }
        if (count($stack) != 0) {
            throw new LogicException('圆括号规则 不正确');
        }
        $childExpressionList[] = $expression;
        return $this->formatExpressionList($childExpressionList);
    }

    protected function replaceChildExpression(string &$expression, array $expressionList, int $childExpressionStartIndex, int $childExpressionLength, int $childExpressionId): array
    {
        $expressionList[$childExpressionId] = substr($expression, $childExpressionStartIndex + 1, $childExpressionLength - 2);
        $expression = $this->lexicalAnalysisTag->replaceTag($expression,
            $childExpressionStartIndex, $childExpressionLength, LexicalAnalysisEnum::TAG_ID_EXPRESSION, $childExpressionId);
        return $expressionList;
    }

    protected function formatExpressionList(array $expressionList): array
    {
        foreach ($expressionList as $key => $expression) {
            $expressionList[$key] = StringUtil::formatExpression($expression);
        }
        return $expressionList;
    }
}